#ifndef __MASK_ALLOC_H__
#define __MASK_ALLOC_H__
#ifdef __cplusplus
extern "C" {
#endif 
#include "buddy.h"
#ifdef __cplusplus
}
#endif 
#include "assert.h"
#include "singleton_t.h"
#include <stdlib.h>

extern int g_dwMemPoolSize;
extern int g_dwMemSliceSize;

#define USE_BUDDY_MEM 1

struct yAlloc
{
	yAlloc()
	:lUse(0)
	,iMax(0)
	,iFail(0)
	,lMaxUse(0)
	,lPtUse(0)
	,lTotal(0)
	,iSlice(0)
	,_buddy(NULL)
	,_data(NULL)
	{
	}
	
	~yAlloc()
	{
#if USE_BUDDY_MEM
		buddy2_destroy(_buddy);
		free(_data);
#endif
	}

	void yInit()
	{
#if USE_BUDDY_MEM
		lTotal = fixsize(g_dwMemPoolSize)*1024L*1024L;
		iSlice = fixsize(g_dwMemSliceSize)*1024;
printf("%ld, %d, %ld\n", lTotal, iSlice, lTotal/iSlice);
		_buddy = buddy2_new(lTotal/iSlice); 
		assert(_buddy);
		_data = (char*)malloc(lTotal);
		assert(_data);
		memset(_data, 0xfe, lTotal);
#endif
	}
	char* yMalloc(int& size)
	{
#if USE_BUDDY_MEM
		int idx = buddy2_alloc(_buddy, 
							((size+iSlice-1)&~(iSlice-1))/iSlice);
		if(idx == -1)
		{
			iFail++;
			lPtUse+=size;
			char* pNew = (char*)malloc(size);
			if(pNew == NULL)
				size = 0;
			return pNew;
		}
		int rSize = buddy2_size(_buddy, idx)*iSlice;
		lUse += rSize;
		if(size > iMax) iMax = size;
		if(lUse > lMaxUse) lMaxUse = lUse;
//printf("mall %p, %d, %d\n", _data+(MEM_SLICE_SIZE*idx), size, rSize);
		size = rSize;
		return _data+(iSlice*idx);
#else
		return (char*)malloc(size);
#endif
	}

	void yFree(char* ptr)
	{
#if USE_BUDDY_MEM
		if(ptr>=_data && ptr<=_data+lTotal)
		{
			int idx = (ptr-_data)/iSlice;
			int rSize = buddy2_size(_buddy, idx)*iSlice;
//printf("free %p, %d\n", ptr, rSize);
			lUse -= rSize;
			buddy2_free(_buddy, idx);
		}
		else
		{
			free(ptr);
		}
#else
		free(ptr);
#endif
	}

	char* yRealloc(char* ptr, int& size)
	{
#if USE_BUDDY_MEM
//printf("realloc\n");
		if(ptr>=_data && ptr<=_data+lTotal)
		{
			char* pNew = yMalloc(size);
			if(pNew == NULL)
			{
				yFree(ptr);
				return NULL;
			}
			char* pOld = ptr;
			int idx = (pOld-_data)/iSlice;
			int rSize = buddy2_size(_buddy, idx)*iSlice;
			memcpy(pNew, pOld, (rSize>size)?size:rSize);
			yFree(pOld);
			return pNew;
		}
		else
		{
			return (char*)realloc(ptr, size);
		}
#else
		return (char*)realloc(ptr, size);
#endif
	}
	
	long lUse;
	int iMax;
	int iFail;
	long lMaxUse;
	long lPtUse;
	long lTotal; //total pool
	int iSlice; //slice size
private:
	unsigned fixsize(unsigned size)
	{
		if(!(size&(size-1)))
			return size;
  		size |= size >> 1;
  		size |= size >> 2;
		size |= size >> 4;
		size |= size >> 8;
 		size |= size >> 16;
  		return size+1;
	}
	struct buddy2* _buddy;
	char*		 _data;
};

typedef CSingletonT<yAlloc> yAllocSingleton;
#define YALLOC yAllocSingleton::Instance()

#endif	
